#include <glad/glad.h>
#include "Mesh.h"

Mesh::Mesh()
{
    _isSetup = false;
}

Mesh::~Mesh()
{
    glDeleteVertexArrays(1, &_VAO);
    glDeleteBuffers(1, &_VBO);
    glDeleteBuffers(1, &_EBO);
}

void Mesh::setVertices(vector<Vertex> vertices)
{
    this->_vertices = vertices;
}
void Mesh::setIndices(vector<unsigned int> indices)
{
    this->_indices = indices;
}

void Mesh::setupMesh()
{
    if(_isSetup)
    {
        glDeleteVertexArrays(1, &_VAO);
        glDeleteBuffers(1, &_VBO);
        glDeleteBuffers(1, &_EBO);
    }
    glGenVertexArrays(1, &_VAO);
    glGenBuffers(1, &_VBO);
    glGenBuffers(1, &_EBO);

    glBindVertexArray(_VAO);

    glBindBuffer(GL_ARRAY_BUFFER, _VBO);
    glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(Vertex), &_vertices[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices.size() * sizeof(unsigned int), &_indices[0], GL_STATIC_DRAW);

    // position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
    glEnableVertexAttribArray(0);
    // color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // texture coord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    _isSetup = true;
}

Mesh *Mesh::createPrimitive(PrimitiveType type)
{
    Mesh *m = nullptr;
    switch (type)
    {
    case PRIMITIVE_QUAD:
        m = _createQuad();
        break;
    case PRIMITIVE_CUBE:
        m = _createCube();
        break;
    }
    return m;
}

Mesh *Mesh::_createQuad()
{
    Mesh *m = new Mesh();
    vector<Vertex> vertices = {
        Vertex{glm::vec3{0.5f, 0.5f, 0.0f}, glm::vec3{1.0f, 1.0f, 1.0f}, glm::vec2{1.0f, 1.0f}},
        Vertex{glm::vec3{0.5f, -0.5f, 0.0f}, glm::vec3{1.0f, 1.0f, 1.0f}, glm::vec2{1.0f, 0.0f}},
        Vertex{glm::vec3{-0.5f, -0.5f, 0.0f}, glm::vec3{1.0f, 1.0f, 1.0f}, glm::vec2{0.0f, 0.0f}},
        Vertex{glm::vec3{-0.5f, 0.5f, 0.0f}, glm::vec3{1.0f, 1.0f, 1.0f}, glm::vec2{0.0f, 1.0f}},
    };

    vector<unsigned int> indices = {
        0, 1, 3, // first triangle
        1, 2, 3  // second triangle
    };

    m->setVertices(vertices);
    m->setIndices(indices);
    m->setupMesh();

    return m;
}

Mesh *Mesh::_createCube()
{
    return nullptr;
}

void Mesh::draw() const
{
    glBindVertexArray(_VAO);
    glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_INT, 0);
}